package hexapawn.game;

import java.util.ArrayList;
import java.util.List;

public class MinimaxTree {
	
	public static final int WIN_FEATURE_VALUE = 10;
	public static final int LOSE_FEATURE_VALUE = 10;
	public static final int DISTANCE_FEATURE_VALUE = 1;
	public static final int PROTECT_FEATURE_VALUE = 1;
	public static final int THREAT_FEATURE_VALUE = 1;
	public static final int PIECE_FEATURE_VALUE = 1;
	

	private Board boardState;
	private MinimaxTree parent;
	private List<MinimaxTree> children;
	
	public MinimaxTree(MinimaxTree parent, Board b ){
		this.boardState = b;
		this.parent = parent;
		this.children = new ArrayList<MinimaxTree>();
	}
	
	public void addChild(MinimaxTree mt){
		this.children.add(mt);
	}
	
	public List<MinimaxTree> getChildren(){
		return children;
	}
	
	public Board getBoard(){
		return boardState;
	}

	
	public int evalFeatures(int player){
		int total = 0;
		total += calculateSelfPieceFeature(player);
		total += calculateOpponentPieceFeature(player);
		total += calculateWinFeature(player);
		total += calculateLoseFeature(player);
		total += calculateThreatFeature(player);
		total += calculateProtectFeature(player);
		total += calculateDistanceFeature(player);
		return total;
	}
	
	private int calculateSelfPieceFeature(int player){
		Board b = this.boardState;
		int count = 0;
		for(int i = 0; i < b.getColumn(); i++ ){
			for(int j = 0; j < b.getRow(); j++){
				Cell c = b.getCells()[i][j];
				if(c.getPiece().getOwner() == player)
					count += PIECE_FEATURE_VALUE;
			}
		}
		return count;
	}
	
	private int calculateOpponentPieceFeature(int player){
		Board b = this.boardState;
		int count = 0;
		for(int i = 0; i < b.getColumn(); i++ ){
			for(int j = 0; j < b.getRow(); j++){
				Cell c = b.getCells()[i][j];
				if(c.getPiece().getOwner() != player)
					count += PIECE_FEATURE_VALUE;
			}
		}
		return count;
	}
	
	private int calculateWinFeature(int player ){
		int winRow = 0;
		switch(player) {
		case Player.PLAYER_1:
		case Player.PLAYER_MDP:
			winRow = 4;
			break;
		case Player.PLAYER_2:
		case Player.PLAYER_MINIMAX:
			winRow = 0;
			break;
		}
		Board b = this.boardState;
		for(int i = 0; i < b.getColumn(); i++){
			if(b.getCells()[winRow][i].getPiece().getOwner() == player)
				return WIN_FEATURE_VALUE;
		}
		return 0;
	}
	
	private int calculateLoseFeature(int player){
		int loseRow = 0;
		switch(player) {
		case Player.PLAYER_1:
		case Player.PLAYER_MDP:
			loseRow = 0;
			break;
		case Player.PLAYER_2:
		case Player.PLAYER_MINIMAX:
			loseRow = 4;
			break;
		}
		Board b = this.boardState;
		for(int i = 0; i < b.getColumn(); i++){
			if(b.getCells()[loseRow][i].getPiece().getOwner() != player)
				return LOSE_FEATURE_VALUE;
		}
		return 0;
	}
	
	private int calculateThreatFeature(int player){
		boolean top = false;
		switch(player) {
		case Player.PLAYER_1:
		case Player.PLAYER_MDP:
			top = true;
			break;
		case Player.PLAYER_2:
		case Player.PLAYER_MINIMAX:
			top = false;
			break;
		}
		Board b = this.boardState;
		int threat = 0;
		for(int i = 0; i < b.getColumn(); i++ ){
			for(int j = 0; j < b.getRow(); j++){
				Cell c = b.getCells()[i][j];
				if(top) {
					if(i > 0 && j > 0) {
						if(b.getCellAboveLeft(c).getPiece().getOwner() != player)
							threat -= THREAT_FEATURE_VALUE;
					}
					if(i < 4 && j > 0 ) {
						if(b.getCellAboveRight(c).getPiece().getOwner() != player)
							threat -= THREAT_FEATURE_VALUE;
					}
				}
				else {
					if(i > 0 && j < 4) {
						if(b.getCellAboveLeft(c).getPiece().getOwner() != player)
							threat -= THREAT_FEATURE_VALUE;
					}
					if(i < 4 && j < 4) {
						if(b.getCellAboveRight(c).getPiece().getOwner() != player)
							threat -= THREAT_FEATURE_VALUE;
					}
				}
			}
		}
		return threat;
	}
	
	private int calculateProtectFeature(int player){
		boolean top = false;
		switch(player) {
		case Player.PLAYER_1:
		case Player.PLAYER_MDP:
			top = true;
			break;
		case Player.PLAYER_2:
		case Player.PLAYER_MINIMAX:
			top = false;
			break;
		}
		Board b = this.boardState;
		int protect = 0;
		for(int i = 0; i < b.getColumn(); i++ ){
			for(int j = 0; j < b.getRow(); j++){
				Cell c = b.getCells()[i][j];
				if(top) {
					if(i > 0 && j > 0) {
						if(b.getCellAboveLeft(c).getPiece().getOwner() == player)
							protect += PROTECT_FEATURE_VALUE;
					}
					if(i < 4 && j > 0 ) {
						if(b.getCellAboveRight(c).getPiece().getOwner() == player)
							protect += PROTECT_FEATURE_VALUE;
					}
				}
				else {
					if(i > 0 && j < 4) {
						if(b.getCellAboveLeft(c).getPiece().getOwner() == player)
							protect += PROTECT_FEATURE_VALUE;
					}
					if(i < 4 && j < 4) {
						if(b.getCellAboveRight(c).getPiece().getOwner() == player)
							protect += PROTECT_FEATURE_VALUE;
					}
				}
			}
		}
		return protect;
	}
	
	private int calculateDistanceFeature(int player ){
		boolean top = false;
		switch(player) {
		case Player.PLAYER_1:
		case Player.PLAYER_MDP:
			top = true;
			break;
		case Player.PLAYER_2:
		case Player.PLAYER_MINIMAX:
			top = false;
			break;
		}
		Board b = this.boardState;
		int distance = 0;
		for(int i = 0; i < b.getColumn(); i++ ){
			for(int j = 0; j < b.getRow(); j++){
				Cell c = b.getCells()[i][j];
				if(c.getPiece().getOwner() == player) {
					if(top)
						distance += (j*DISTANCE_FEATURE_VALUE)*(j*DISTANCE_FEATURE_VALUE);
					else
						distance += ((4 - j)*DISTANCE_FEATURE_VALUE)*((4 - j)*DISTANCE_FEATURE_VALUE);
				}
			}
		}
		return distance;
	}

}
